package main

import (
	"flag"
	"fmt"
)

var block = "package"
var container = []string{"零", "一", "二"}

func main() {
	//Go 语言中短变量声明的类型推断可以带来哪些好处？
	//可以随意改变getTheFlag函数的内部实现，及其返回结果的类型，而不用修改main函数中的任何代码
	//不显式地指定变量name的类型，使得它可以被赋予任何类型的值。也就是变量name的类型可以在其初始化时，由其他程序动态地确定。
	var name1 = getTheFlag1()
	var name2 = getTheFlag2()
	flag.Parse()
	fmt.Printf("Hello, %v!\n", *name1)
	fmt.Printf("Hello, %v!\n", *name2)

	//代码块
	block := "function"
	{
		block := "inner"
		fmt.Printf("The block is %s.\n", block) //The block is inner.
	}
	fmt.Printf("The block is %s.\n", block) //The block is function.

	//不同代码块中的重名变量
	container := map[int]string{0: "zero", 1: "one", 2: "two"}
	fmt.Printf("The element is %q.\n", container[1]) //The element is "one".

	//判断变量的类型
	elem, err := getElement(container)
	fmt.Println(elem)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		return
	}
	fmt.Printf("container type: %T \n", container) //container type: map[int]string
}

func getTheFlag1() *string {
	return flag.String("name", "everyone", "The greeting object.")
}

func getTheFlag2() *int {
	return flag.Int("num", 100, "The number of greeting object.")
}

func getElement(containerI interface{}) (elem string, err error) {
	switch t := containerI.(type) {
	case []string:
		elem = t[1]
	case map[int]string:
		elem = t[1]
	default:
		err = fmt.Errorf("unsupported container type: %T", containerI)
		return
	}
	return
}

// 代码块
type T struct {
	name string
}

func (t T) blockDemo(x int) (err error) {
	// 代码块1
	m := 13
	fmt.Println(m)
	// 代码块1是包含m、t、x和err三个标识符的最内部代码块
	{ // 代码块2
		// "代码块2"是包含类型bar标识符的最内部的那个包含代码块
		type bar struct{} // 类型标识符bar的作用域始于此
		{                 // 代码块3
			// "代码块3"是包含变量a标识符的最内部的那个包含代码块
			a := 5 // a作用域开始于此
			{      // 代码块4
				fmt.Println(a)
			}
			// a作用域终止于此
		}
		// 类型标识符bar的作用域终止于此
	}
	// m、t、x和err的作用域终止于此
	return nil
}
